<?php
/**
 * Created by PhpStorm.
 * User: lf
 * Date: 2018/1/12
 * Time: 17:33
 */

namespace AppBundle\Service;

use AppBundle\Service\lib\IAuth;
use AppBundle\Service\lib\Aes;
use AppBundle\Service\lib\Time;
use AppBundle\Service\lib\Sms;
/**
 * Class CommonService
 * @package AppBundle\Service
 * @abstract 通用函数的服务类，其中对应的函数是自定义的一些通用函数，在控制器的任何地方都可能使用到
 */
class CommonService{


    /**
     * @abstract redis的访问ip
     * @var string
     */
    private $_strRedisHost = '';


    /**
     * @abstract redis的访问端口
     * @var string
     */
    private $_sreRedisPort = '';


    /**
     * @abstract api请求的时间限制
     * @var int
     */
    private $_intDeadTime = 10;


    /**
     * CommonService constructor.
     * @param $__strRedisHost  redis的访问ip
     * @param $__strRedisPort  redis的开启端口
     */
    public function __construct($__strRedisHost,$__strRedisPort,$__intDeadTime)
    {
        $this->_sreRedisPort = $__strRedisPort;
        $this->_strRedisHost = $__strRedisHost;
        $this->_intDeadTime = $__intDeadTime;
    }


    /**
     * @author lf
     * @param $arrData 待处理的数组
     * @abstract 在页面上拼接字符串的时候‘&’字符串在html中会被转义为‘&amp;’，这个函数就是为了处理在控制器中获得了参数传递之后
     * 将对应的'&amp;'转换为‘&’
     */
    public function build_query($arrData){
        foreach($arrData as $key=>$value){
            if(strpos($key,'amp;') !== false){//存在
                $_strNewKey = str_replace('amp;','',$key);
                $arrData[$_strNewKey] = $value;
                unset($arrData[$key]);
            }
        }
        return $arrData;
    }

    /**
     * @abstract api接口返回的统一封装函数
     * @param $intStatus  业务状态码
     * @param $strMessage 描述信息
     * @param $arrData 数据
     * @param int $intHttpCode http状态码
     */
    public function apiEnCode($intStatus,$strMessage,$arrData,$intHttpCode = 200){
        //封装返回数据
        $arrReturnData = array(
            'status' => $intStatus,
            'message' => $strMessage,
            'data' => $arrData,
            'httpcode' => $intHttpCode
        );
        return json_encode($arrReturnData);
    }


    /**
     * @abstract 加密sign的函数
     * @param $arrData
     * @return string
     */
    public function encryptSign($arrData){
        $_objIAuth = new IAuth();
        $_strSign = $_objIAuth->setSign($arrData);
        return $_strSign;
    }

    /**
     * @abstract 解密sign的函数
     * @param $strString
     * @return String
     */
    public function decryptSign($strString){
        $_objAes = new Aes();
        $_strString  = $_objAes->decrypt($strString);
        return $_strString;
    }


    /**
     * @abstract 校验sign的合法性
     * @param $data
     * @return bool
     */
    public function checkSignPass($data){
        //首先解密发送过来的sign
        $strSign = $this->decryptSign($data->get('sign'));
        if(empty($strSign)){//sign验签为空
            return false;
        }
        //判断sign解密的参数值是都和传递的参数值是一致的
        parse_str($strSign,$arrData);
        if(!is_array($arrData) || empty($arrData['did']) || $data->get('did') != $arrData['did']){
            return false;
        }
        //还需要校验时间戳，也就是这个请求需要在规定时间内获得响应否则就失效
     /*   if((time() - ceil($arrData['time']/1000)) > $this->_intDeadTime){
            return false;
        }*/
        return true;
    }

    /**
     * @abstract 获取13位的时间戳
     * @return int
     */
    public function get13TimeStamp(){
        return Time::get13TimeStamp();
    }


    /**
     * @abstract 使用redis存储验签sign的值
     * @param $request
     * @return bool
     */
    function saveSignByRedis($request){
        $_objHeader = $request->headers;
        $redis = new \Redis();
        $redis->connect($this->_strRedisHost, $this->_sreRedisPort);
        $_strSign = $_objHeader->get('sign');
        //首先判断是否存在在集合中不存在的情况下新增一下
        if($redis->sIsMember('all_request',$_strSign)){//已经存在那么不在存储这条记录同时说明请求不合法
            return false;
        }else{
            $intCount = $redis->sAdd('all_request',$_strSign);
            if($intCount != 0){//说明成功的新增
                return true;
            }else{
                return false;
            }
        }
    }

    /**
     * @abstract 函数用来存储header头中的某一个具体的信息，上面的函数saveSignByRedis的功能可以使用当前的这个函数进行替代，只是调用发放要做一定的修改
     * @param $_strStoreInfo 存储值
     * @param $__strStoreKey 存储键值，当前查询出来的键值
     */
    function saveInfoByRedis($_strStoreInfo,$__strStoreKey){
        $redis = new \Redis();
        $redis->connect($this->_strRedisHost, $this->_sreRedisPort);
        //判断是否存在在集合中不存在的情况下新增一下
        if($redis->sIsMember($__strStoreKey,$_strStoreInfo)){//已经存在那么不在存储这条记录同时说明请求不合法
            return false;
        }else{
            $intCount = $redis->sAdd($__strStoreKey,$_strStoreInfo);
            if($intCount != 0){//说明成功的新增
                return true;
            }else{
                return false;
            }
        }
    }

    /**
     * @abstract 短信验证码发送
     * @param $__strCode
     */
    public  function  sendCodeSms($__strCode,$__strPhone){
        $request = new Sms();
        $_objReturn = $request->sendCodeSms($__strCode,$__strPhone);
        if($_objReturn->Code == 'OK'){//短信发送成功
            //在短信发送成功的情况下使用session存储短信验证码，并设置失效时间，这里使用电话号码设置两个键值
            $_SESSION[$__strPhone."validatecode"] = $__strCode;
//            $_SESSION[$__strPhone."validatecode_timeout"] = strtotime('+5 miunte');
            $_SESSION[$__strPhone."validatecode_timeout"] = strtotime('+ 1 day');
            return $this->apiEnCode(1,'短信发送成功','',200);
        }else{//短信发送失败
            return $this->apiEnCode(0,'短信发送失败','',404);
        }
    }

    /**
     * @author LF
     * @param $__strPhone 当前需要校验的短信验证码的发送手机号
     */
    public function getCodeSms($__strPhone){
        //判断当前时间和session中存储的有关当前电话验证码的过期时间的大小关系，当前时间大于过期时间的情况下
        //清空验证码和对应的过期时间并返回空的验证码
        if(array_key_exists($__strPhone.'validatecode',$_SESSION)){//拼接键值存在
            //判断过期时间是否存在
            if(array_key_exists($__strPhone.'validatecode_timeout',$_SESSION)){
                if(time() > $_SESSION[$__strPhone.'validatecode_timeout']){//当前时间大于短信验证码的失效时间
                    //将原来的验证码和失效时间处理掉
                    $_SESSION[$__strPhone."validatecode"] = '';
                    $_SESSION[$__strPhone."validatecode_timeout"] = 0;
                    //返回空值
                    return '';
                }else{
                    return $_SESSION[$__strPhone."validatecode"];
                }
            }else{
                return '';
            }
        }else{
            return '';
        }
    }

    /**
     * @abstract 函数用来生成的随机字符串
     * @param int $length 随机字符串的长度
     * @param int $mode 选择的生成模式  0为大小写英文和数字,1为数字,2为小写字母,3为大写字母,
     * 4为大小写字母,5为大写字母和数字,6为小写字母和数字
     * @return string
     */
    function get_code($length=32,$mode=0)//获取随机验证码函数
    {
        switch ($mode)
        {
            case '1':
                $str='1234567890';
                break;
            case '2':
                $str='abcdefghijklmnopqrstuvwxyz';
                break;
            case '3':
                $str='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
                break;
            case '4':
                $str='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
                break;
            case '5':
                $str='ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
                break;
            case '6':
                $str='abcdefghijklmnopqrstuvwxyz1234567890';
                break;
            default:
                $str='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
                break;
        }
        $checkstr='';
        $len=strlen($str)-1;
        for ($i=0;$i<$length;$i++)
        {
            //$num=rand(0,$len);//产生一个0到$len之间的随机数
            $num=mt_rand(0,$len);//产生一个0到$len之间的随机数
            $checkstr.=$str[$num];
        }
        return $checkstr;
    }

    /**
     * @abstract 返回app用户登录的token
     * @param $__strPhone
     * @return string
     */
    public function getAppLoginToken($__strPhone){
        $_strToken = '';
        $_strToken = IAuth::setApploginToken($__strPhone);
        return $_strToken;
    }

}